package com.sx.core.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by lihao on 2018/4/4.
 */
public class WxPayUtils {
    private static Log log= LogFactory.getLog(WxPayUtils.class);
    static HttpClientInstance httpClientInstance=HttpClientInstance.getInstance();
    static String SUCCESS="SUCCESS";
    public static String nonStr(){
        String $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        int maxPos = $chars.length();
        String noceStr = "";
        for (int i = 0; i < 32; i++) {
            noceStr += $chars.charAt((int)Math.floor(Math.random() * maxPos));
        }
        return noceStr;
    }
    //商户对账--服务商
    public static String billService(String appid,String mch_id,String key,String sub_appid,String sub_mch_id,String bill_date,String bill_type){
        String url="https://api.mch.weixin.qq.com/pay/downloadbill";
        String nonce_str=nonStr();
        StringBuffer sb=new StringBuffer();
        sb.append("appid=").append(appid).append("&");
        sb.append("bill_date=").append(bill_date).append("&");
        sb.append("bill_type=").append(bill_type).append("&");
        sb.append("mch_id=").append(mch_id).append("&");
        sb.append("nonce_str=").append(nonce_str).append("&");
        sb.append("sub_appid=").append(sub_appid).append("&");
        sb.append("sub_mch_id=").append(sub_mch_id).append("&");
        sb.append("key=").append(key);
        String sign=Md5.md5(sb.toString()).toUpperCase();

        StringBuffer xml=new StringBuffer();
        xml.append("<xml>");
        xml.append("<appid>").append(appid).append("</appid>");
        xml.append("<bill_date>").append(bill_date).append("</bill_date>");
        xml.append("<bill_type>").append(bill_type).append("</bill_type>");
        xml.append("<mch_id>").append(mch_id).append("</mch_id>");
        xml.append("<nonce_str>").append(nonce_str).append("</nonce_str>");
        xml.append("<sub_appid>").append(sub_appid).append("</sub_appid>");
        xml.append("<sub_mch_id>").append(sub_mch_id).append("</sub_mch_id>");
        xml.append("<sign>").append(sign).append("</sign>");
        xml.append("</xml>");
        return httpClientInstance.postString(url,xml.toString());
    }
    //服务商微信公众号支付
    public static Map<String,String> getServiceWechatPay(String appid, String mch_id, String sub_appid, String sub_mch_id, String key, String body, String out_trade_no, String total_fee, String spbill_create_ip, String notify_url, String openid, String sub_openid){

        String nonce_str=nonStr();
        String trade_type="JSAPI";
        StringBuffer sb=new StringBuffer();
        sb.append("appid=").append(appid).append("&");
        sb.append("body=").append(body).append("&");
        sb.append("mch_id=").append(mch_id).append("&");
        sb.append("nonce_str=").append(nonce_str).append("&");
        sb.append("notify_url=").append(notify_url).append("&");
        if(StringUtils.isNotBlank(openid)){
            sb.append("openid=").append(openid).append("&");
        }
        sb.append("out_trade_no=").append(out_trade_no).append("&");
        sb.append("spbill_create_ip=").append(spbill_create_ip).append("&");
        sb.append("sub_appid=").append(sub_appid).append("&");
        sb.append("sub_mch_id=").append(sub_mch_id).append("&");
        if(StringUtils.isNotBlank(sub_openid)){
            sb.append("sub_openid=").append(sub_openid).append("&");
        }
        sb.append("total_fee=").append(total_fee).append("&");
        sb.append("trade_type=").append(trade_type).append("&");
        sb.append("key=").append(key);
        String sign=Md5.md5(sb.toString()).toUpperCase();



        //预支付
        String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
        sb=new StringBuffer();
        sb.append("<xml>");
        sb.append("<appid>").append(appid).append("</appid>");
        sb.append("<mch_id>").append(mch_id).append("</mch_id>");
        sb.append("<nonce_str>").append(nonce_str).append("</nonce_str>");
        sb.append("<sign>").append(sign).append("</sign>");
        sb.append("<body>").append(body).append("</body>");
        sb.append("<out_trade_no>").append(out_trade_no).append("</out_trade_no>");
        sb.append("<total_fee>").append(total_fee).append("</total_fee>");
        sb.append("<spbill_create_ip>").append(spbill_create_ip).append("</spbill_create_ip>");
        sb.append("<sub_appid>").append(sub_appid).append("</sub_appid>");
        sb.append("<sub_mch_id>").append(sub_mch_id).append("</sub_mch_id>");
        if(StringUtils.isNotBlank(sub_openid)){
            sb.append("<sub_openid>").append(sub_openid).append("</sub_openid>");
        }

        sb.append("<notify_url>").append(notify_url).append("</notify_url>");
        sb.append("<trade_type>").append(trade_type).append("</trade_type>");
        if(StringUtils.isNotBlank(openid)){
            sb.append("<openid>").append(openid).append("</openid>");
        }

        sb.append("</xml>");
        String xml= httpClientInstance.postString(url,sb.toString());


        log.info("create preid xml "+xml);
        Element element= parseXml(xml);
        if(element==null){
            return null;
        }
        String return_code=element.elementText("return_code");
        String result_code=element.elementText("result_code");
        if(!StringUtils.equals(SUCCESS,return_code) || !StringUtils.equals(SUCCESS,result_code)){
            return null;
        }
        String prepay_id=element.elementText("prepay_id");
        if(StringUtils.isEmpty(prepay_id)){
            return null;
        }
        log.info("prepay_id===="+prepay_id);

        String timestamp=System.currentTimeMillis()+"";
        timestamp=timestamp.substring(0,10);
        StringBuffer newSign=new StringBuffer();
        newSign.append("appId=").append(appid).append("&");
        newSign.append("nonceStr=").append(nonce_str).append("&");
        newSign.append("package=").append("prepay_id=").append(prepay_id).append("&");
        newSign.append("signType=").append("MD5").append("&");
        newSign.append("timeStamp=").append(timestamp).append("&");
        newSign.append("key=").append(key);
        String sign_new=Md5.md5(newSign.toString()).toUpperCase();
        Map map=new HashMap();
        map.put("appId",appid);
        map.put("nonceStr",nonce_str);
        map.put("package","prepay_id="+prepay_id);
        map.put("timeStamp",timestamp);
        map.put("paySign",sign_new);
        return map;
    }
    public static void main(String[] args){
        Map result=getServiceAppPay("wx13193acb942c1ef9","1489332352","wx6188a3d704a1ec96","1502153371","3b17505e4aff806c8fcfc9710afd14aa","ces","3333iok222","1","120.26.13.238","http://sccdsdzx.55clouds.com/notify/wx");
//        Map result1=getServiceWechatPay("wx13193acb942c1ef9","1489332352","wxae541ef2c3a26fa6","1489609002","3b17505e4aff806c8fcfc9710afd14aa","ces","3333iok222","1","120.26.13.238","http://sccdsdzx.55clouds.com/notify/wx","","oppFE0khv3lJLh8o9A5v4AxFGzXE");



        System.out.println("dddd");


    }
    //服务商App支付
    public static Map<String,String> getServiceAppPay(String appid,String mch_id,String sub_appid,String sub_mch_id,String key,String body,String out_trade_no,String total_fee,String spbill_create_ip,String notify_url){

        String nonce_str=nonStr();
        String trade_type="APP";
        StringBuffer sb=new StringBuffer();
        sb.append("appid=").append(appid).append("&");
        sb.append("body=").append(body).append("&");
        sb.append("mch_id=").append(mch_id).append("&");
        sb.append("nonce_str=").append(nonce_str).append("&");
        sb.append("notify_url=").append(notify_url).append("&");
        sb.append("out_trade_no=").append(out_trade_no).append("&");
        sb.append("spbill_create_ip=").append(spbill_create_ip).append("&");
        sb.append("sub_appid=").append(sub_appid).append("&");
        sb.append("sub_mch_id=").append(sub_mch_id).append("&");
        sb.append("total_fee=").append(total_fee).append("&");
        sb.append("trade_type=").append(trade_type).append("&");
        sb.append("key=").append(key);
        String sign=Md5.md5(sb.toString()).toUpperCase();

        String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
        StringBuffer xml=new StringBuffer();
        xml.append("<xml>");
        xml.append("<appid>").append(cdata(appid)).append("</appid>");
        xml.append("<body>").append(cdata(body)).append("</body>");
        xml.append("<mch_id>").append(cdata(mch_id)).append("</mch_id>");
        xml.append("<nonce_str>").append(cdata(nonce_str)).append("</nonce_str>");
        xml.append("<notify_url>").append(cdata(notify_url)).append("</notify_url>");
        xml.append("<out_trade_no>").append(cdata(out_trade_no)).append("</out_trade_no>");



        xml.append("<spbill_create_ip>").append(cdata(spbill_create_ip)).append("</spbill_create_ip>");
        xml.append("<sub_appid>").append(cdata(sub_appid)).append("</sub_appid>");
        xml.append("<sub_mch_id>").append(cdata(sub_mch_id)).append("</sub_mch_id>");
        xml.append("<total_fee>").append(cdata(total_fee)).append("</total_fee>");
        xml.append("<trade_type>").append(cdata(trade_type)).append("</trade_type>");
        xml.append("<sign>").append(cdata(sign)).append("</sign>");
        xml.append("</xml>");
        String xml_str=httpClientInstance.postString(url,xml.toString());

        log.info("create preid xml getServiceAppPay>>>"+xml_str);
        Element element= parseXml(xml_str);
        if(element==null){
            return null;
        }
        String return_code=element.elementText("return_code");
        String result_code=element.elementText("result_code");

        if(!StringUtils.equals(SUCCESS,return_code) || !StringUtils.equals(SUCCESS,result_code)){
            return null;
        }
        String prepay_id=element.elementText("prepay_id");
        if(StringUtils.isEmpty(prepay_id)){
            return null;
        }
        log.info("prepay_id===="+prepay_id);

        String timestamp=System.currentTimeMillis()+"";
        timestamp=timestamp.substring(0,10);
        StringBuffer newSign=new StringBuffer();
        newSign.append("appid=").append(sub_appid).append("&");
        newSign.append("noncestr=").append(nonce_str).append("&");
        newSign.append("package=").append("Sign=WXPay").append("&");
        newSign.append("partnerid=").append(sub_mch_id).append("&");
        newSign.append("prepayid=").append(prepay_id).append("&");
        newSign.append("timestamp=").append(timestamp).append("&");
        newSign.append("key=").append(key);
        String sign_new= Md5.md5(newSign.toString()).toUpperCase();
        Map map=new HashMap();
        map.put("appid",sub_appid);
        map.put("partnerid",sub_mch_id);
        map.put("prepayid",prepay_id);
        map.put("package","Sign=WXPay");
        map.put("noncestr",nonce_str);
        map.put("timestamp",timestamp);
        map.put("sign",sign_new);
        return map;
    }
    private static String cdata(String str){
        return "<![CDATA["+str+"]]>";
    }


    static String IOS="IOS";
    static String Android="Android";
    static String Wap="Wap";
    private String scene_info(String type){
        Map scene_info_map=new HashMap();
        Map h5_info_map=new HashMap();
        if(StringUtils.equals(type,IOS)){
            h5_info_map.put("type",IOS);
            h5_info_map.put("bundle_id",IOS);
            h5_info_map.put("app_name",IOS);
        }else if(StringUtils.equals(type,Android)){
            h5_info_map.put("type",Android);
            h5_info_map.put("package_name",IOS);
            h5_info_map.put("app_name",IOS);
        }else if(StringUtils.equals(type,Wap)){
            h5_info_map.put("type",Wap);
            h5_info_map.put("wap_url","http://wxh5.55clouds.com");
            h5_info_map.put("wap_name","一卡通充值");
        }
        scene_info_map.put("h5_info",h5_info_map);
        return JSON.toJSONString(scene_info_map);
    }
    //服务商h5支付
    public Map<String,String> getServiceH5Pay(String appid,String mch_id,String sub_appid,String sub_mch_id,String key,String body,String out_trade_no,String total_fee,String spbill_create_ip,String notify_url,String scene_info_type){


        String nonce_str=nonStr();
        String trade_type="MWEB";
        String scene_info=scene_info(scene_info_type);
        StringBuffer sb=new StringBuffer();
        sb.append("appid=").append(appid).append("&");
        sb.append("body=").append(body).append("&");
        sb.append("mch_id=").append(mch_id).append("&");
        sb.append("nonce_str=").append(nonce_str).append("&");
        sb.append("notify_url=").append(notify_url).append("&");
        sb.append("out_trade_no=").append(out_trade_no).append("&");
        sb.append("scene_info=").append(scene_info).append("&");
        sb.append("spbill_create_ip=").append(spbill_create_ip).append("&");
        sb.append("sub_appid=").append(sub_appid).append("&");
        sb.append("sub_mch_id=").append(sub_mch_id).append("&");
        sb.append("total_fee=").append(total_fee).append("&");
        sb.append("trade_type=").append(trade_type).append("&");
        sb.append("key=").append(key);
        String sign=Md5.md5(sb.toString()).toUpperCase();


        String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
        StringBuffer xml=new StringBuffer();
        xml.append("<xml>");
        xml.append("<appid>").append(appid).append("</appid>");
        xml.append("<body>").append(body).append("</body>");
        xml.append("<mch_id>").append(mch_id).append("</mch_id>");
        xml.append("<nonce_str>").append(nonce_str).append("</nonce_str>");
        xml.append("<notify_url>").append(notify_url).append("</notify_url>");
        xml.append("<out_trade_no>").append(out_trade_no).append("</out_trade_no>");
        xml.append("<scene_info>").append(scene_info).append("</scene_info>");
        xml.append("<sign>").append(sign).append("</sign>");
        xml.append("<spbill_create_ip>").append(spbill_create_ip).append("</spbill_create_ip>");
        xml.append("<sub_appid>").append(sub_appid).append("</sub_appid>");
        xml.append("<sub_mch_id>").append(sub_mch_id).append("</sub_mch_id>");
        xml.append("<total_fee>").append(total_fee).append("</total_fee>");
        xml.append("<trade_type>").append(trade_type).append("</trade_type>");
        xml.append("</xml>");
        String xml_str=httpClientInstance.postString(url,xml.toString());

        log.info("create preid xml getServiceH5Pay>>>"+xml_str);
        Element element= parseXml(xml_str);
        if(element==null){
            return null;
        }
        String return_code=element.elementText("return_code");
        String result_code=element.elementText("result_code");

        if(!StringUtils.equals(SUCCESS,return_code) || !StringUtils.equals(SUCCESS,result_code)){
            return null;
        }
        String prepay_id=element.elementText("prepay_id");
        if(StringUtils.isEmpty(prepay_id)){
            return null;
        }
        log.info("prepay_id===="+prepay_id);
        String mweb_url=element.elementText("mweb_url");
        if(StringUtils.isEmpty(mweb_url)){
            return null;
        }
        log.info("mweb_url===="+mweb_url);

        Map map=new HashMap();
        map.put("mweb_url",mweb_url);
        return map;
    }
    //服务商二维码支付
    public Map<String,String> getServiceQrPay(String appid,String mch_id,String sub_appid,String sub_mch_id,String key,String body,String out_trade_no,String total_fee,String spbill_create_ip,String notify_url,String product_id){

        String nonce_str=nonStr();
        String trade_type="NATIVE";
        StringBuffer sb=new StringBuffer();
        sb.append("appid=").append(appid).append("&");
        sb.append("body=").append(body).append("&");
        sb.append("mch_id=").append(mch_id).append("&");
        sb.append("nonce_str=").append(nonce_str).append("&");
        sb.append("notify_url=").append(notify_url).append("&");
//        sb.append("openid=").append(openid).append("&");
        sb.append("out_trade_no=").append(out_trade_no).append("&");
        sb.append("product_id=").append(product_id).append("&");
        sb.append("spbill_create_ip=").append(spbill_create_ip).append("&");
        sb.append("sub_appid=").append(sub_appid).append("&");
        sb.append("sub_mch_id=").append(sub_mch_id).append("&");
//        sb.append("sub_openid=").append(sub_openid).append("&");
        sb.append("total_fee=").append(total_fee).append("&");
        sb.append("trade_type=").append(trade_type).append("&");
        sb.append("key=").append(key);
        String sign=Md5.md5(sb.toString()).toUpperCase();



        String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
        sb=new StringBuffer();
        sb.append("<xml>");
        sb.append("<appid>").append(appid).append("</appid>");
        sb.append("<mch_id>").append(mch_id).append("</mch_id>");
        sb.append("<nonce_str>").append(nonce_str).append("</nonce_str>");
        sb.append("<sign>").append(sign).append("</sign>");
        sb.append("<body>").append(body).append("</body>");
        sb.append("<out_trade_no>").append(out_trade_no).append("</out_trade_no>");
        sb.append("<product_id>").append(product_id).append("</product_id>");
        sb.append("<total_fee>").append(total_fee).append("</total_fee>");
        sb.append("<spbill_create_ip>").append(spbill_create_ip).append("</spbill_create_ip>");
        sb.append("<sub_appid>").append(sub_appid).append("</sub_appid>");
        sb.append("<sub_mch_id>").append(sub_mch_id).append("</sub_mch_id>");
        sb.append("<notify_url>").append(notify_url).append("</notify_url>");
        sb.append("<trade_type>").append(trade_type).append("</trade_type>");
//        sb.append("<openid>").append(openid).append("</openid>");
        sb.append("</xml>");
        String xml= httpClientInstance.postString(url,sb.toString());

        log.info("create preid xml "+xml);
        Element element= parseXml(xml);
        if(element==null){
            return null;
        }
        String return_code=element.elementText("return_code");
        String result_code=element.elementText("result_code");
        if(StringUtils.isEmpty(result_code) || StringUtils.isEmpty(return_code)){
            return null;
        }
        String prepay_id=element.elementText("prepay_id");
        if(StringUtils.isEmpty(prepay_id)){
            return null;
        }
        String code_url=element.elementText("code_url");
        if(StringUtils.isEmpty(code_url)){
            return null;
        }

        log.info("prepay_id===="+prepay_id);

//        QrUtils.createQr(code_url,200,200,new File("/Users/lihao/Downloads/test_pay.png"));


        String timestamp=System.currentTimeMillis()+"";
        timestamp=timestamp.substring(0,10);
        StringBuffer newSign=new StringBuffer();
        newSign.append("appId=").append(appid).append("&");
        newSign.append("nonceStr=").append(nonce_str).append("&");
        newSign.append("package=").append("prepay_id=").append(prepay_id).append("&");
        newSign.append("signType=").append("MD5").append("&");
        newSign.append("timeStamp=").append(timestamp).append("&");
        newSign.append("key=").append(key);
        String sign_new=Md5.md5(newSign.toString()).toUpperCase();
        Map map=new HashMap();
        map.put("appId",appid);
        map.put("nonceStr",nonce_str);
        map.put("package","prepay_id="+prepay_id);
        map.put("timeStamp",timestamp);
        map.put("paySign",sign_new);
        return map;
    }

    public static Element parseXml(String xml){
        if(xml==null){
            return null;
        }
        try {
            Document document = DocumentHelper.parseText(xml);
            Element element = document.getRootElement();
            return element;
        } catch (DocumentException e) {
        } catch (Exception e) {
        }
        return null;
    }
    public static boolean verifySign(String xml,String key) throws Exception {
        Element element=parseXml(xml);
        return verifySign(element,key);
    }
    public static boolean verifySign(Element element,String key) {
        if(element==null){
            return false;
        }
        List<Element> elements=element.elements();
        StringBuffer sb=new StringBuffer();
        for(Element el:elements){
            String name = el.getName();
            String value=element.elementText(name);
            if(name.equals("sign")){
                continue;
            }
            sb.append("&");
            sb.append(name).append("=").append(value);
        }
        sb.append("&key="+key);
        String my_sign=null;
        if(sb.length()>1){
            my_sign=Md5.md5(sb.substring(1));
        }
        return StringUtils.equals(my_sign,element.elementText("sign"));
    }
    public static boolean checkSuccess(Element element){
        return element != null && StringUtils.equalsIgnoreCase("SUCCESS", element.elementText("return_code")) && StringUtils.equalsIgnoreCase("SUCCESS", element.elementText("result_code"));
    }
}
